package com.gton.person.config;

import com.gton.person.commons.captcha.CaptchaAuthenticationProvider;
import com.gton.person.commons.captcha.CaptchaRepository;
import com.gton.person.commons.captcha.RedisCaptchaRepository;
import com.gton.person.commons.hander.CaptchaAuthenticationDetailsSource;
import com.gton.person.service.impl.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.servlet.http.HttpServletRequest;

/**
 * @program: PersonalDesign
 * @description: Security 配置文件
 * @author: GuoTong
 * @create: 2020-11-16 16:56
 **/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired  //    @Resource
    private UserService userService;


    //授权，链式编程
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //首页所有人都可访问，功能页只能有对应权限才能访问.permitAll()
        //配置请求授权的规则
        http.authorizeRequests().
                mvcMatchers("/", "/swagger-resources/configuration/ui",
                        "/test/**",
                        "/register",
                        "/captcha",
                        "/oss",
                        "/swagger-resources",
                        "/swagger-resources/configuration/security",
                        "/swagger-ui.html",
                        "/v2/api-docs/*",
                        "/css/**",
                        "/js/**",
                        "/images/**",
                        "/webjars/**",
                        "/import/test",
                        "/bootstrap-3.3.7-dist/**",
                        "**/favicon.ico").permitAll()//放行前面的资源||下边的需要权限
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        //没有权限则跳转到登录页面，需开启登录页面，默认为/login请求，可自定义登录页
        http.formLogin().
                loginPage("/toLogin").failureUrl("/login/error").
                authenticationDetailsSource(new CaptchaAuthenticationDetailsSource(redisCaptchaRepository())).and()
                .authenticationProvider(new CaptchaAuthenticationProvider());
        //关闭csrf功能，注销操作失败可能是开启了csrf
        http.csrf().disable();
        //开启注销操作，并定制注销跳转页面
        http.logout().logoutSuccessUrl("/index");
        //自定义开启记住我功能  cookie，默认保存两周
        http.rememberMe().rememberMeParameter("rememberMe");
    }

    //认证，springboot2.1.x可直接使用
    //密码编码异常--PasswordEncoder，即提示需要使用密码加密
    //在SpringSecurity5.0+版本中，新增 md5、base64等众多加密方式
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //在缓存中模拟添加用户+角色，正常应该从数据库中读取
      /* auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("swpuchenxinde1").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3").and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3").and()
                .withUser("swpuchenxinde2").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");*/

        //不写此处在使用rememberMe功能时会出现异常：UserDetailsService is required.
        System.out.println("进入授权管理");
        auth.userDetailsService(userService);
    }


    /**
     * 不写此方法passwordEncoder会抛java.lang.IllegalArgumentException:
     * There is no PasswordEncoder mapped for the id "null"
     * 因为SpringSecurity新版本需使用密码加密
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /*验证码验证加入springsecurity的登录:这里使用redis仓库。可以使用session*/
    @Bean
    public CaptchaRepository<HttpServletRequest> redisCaptchaRepository() {
        return new RedisCaptchaRepository();
    }

//    忽略验证码的请求：
/*    @Override
    public void configure(WebSecurity web) {
        web.ignoring()
                .mvcMatchers("/");
    }*/
}

